package com.qdd.freight.config;

import com.qdd.freight.anno.Mode;
import com.qdd.freight.exception.NullDesignatedHandlerException;
import com.qdd.freight.handler.AbstractHandler;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;

import java.util.HashMap;
import java.util.Map;

/**
 * 核心类：
 * 1.扫描处理器的实现类，创建单例对象，在springboot启动时放入容器中；
 * 2.根据注解值找到对应处理器的字节码，从容器中取出处理器实例；
 * <p>
 * * @ClassName HandlerContext
 * * @Description DONE
 * * @Author peijie
 * * @Date 2019/12/8 20:59
 * * @Version 1.0
 */
@Component
public class HandlerContext implements ApplicationContextAware {

    @Autowired
    private ApplicationContext applicationContext;
    private static final Map<String, Class> handlerMap = new HashMap<>();

    /**
     * 类型作为key，handler实例的class字节码对象作为value存入map
     *
     * @param applicationContext
     * @throws BeansException
     */
    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        // 遍历带有HandlerType注释的类,存入map
        Map<String, Object> beansMap = applicationContext.getBeansWithAnnotation(Mode.class);
        if (beansMap != null && beansMap.size() > 0) {
            for (Object handlerBean : beansMap.values()) {
                String handlerType = handlerBean.getClass().getAnnotation(Mode.class).value();
                handlerMap.put(handlerType, handlerBean.getClass());
            }
        }
    }

    /**
     * 根据类型对应的处理器类的字节码对象从容器中获取对应的处理器实例
     * 先从stratory工厂的map中获取，如果获取不到再从spring容器中获取。
     * <p>
     * TODO 需要测试一下抛出异常是否正确
     *
     * @param mode
     * @return
     */
    public AbstractHandler getHandlerInstance(String mode) {
        AbstractHandler handlerInstance = null;
        try {
            //从工厂的map中获取处理器实例
            handlerInstance = StrategyFactory.getHandlerBeanByType(mode);
            if (handlerInstance == null) {
                //map中不存在，根据处理器的class再从spring容器中获取
                Class<? extends AbstractHandler> clazz = handlerMap.get(mode);
                handlerInstance = applicationContext.getBean(clazz);
            }
        } catch (NullDesignatedHandlerException e) {
            //都为获取到抛出异常
            e.printStackTrace();
            throw new IllegalArgumentException(e);
        }
        return handlerInstance;
    }
}